《剑指offer》 15.二进制中1的个数

note:两个特质:

  • 与运算的定义:
    • 若$n\&1=0$,则$n$的二进制中最右一位为0
    • 若$n\&1=1$,则$n$的二进制中最右一位为1
  • $n\&(n-1)$:表示二进制数字$n$最右边的1变为0,其余不变
    • 因为$(n-1)$表示二进制数字$n$最右边的1变为0,此1右边的0都变为1

题目描述

请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:

1
2
3
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

示例 2:

1
2
3
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。

示例 3:

1
2
3
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

提示:

  • 输入必须是长度为 32 的 二进制串 。

方法一:按位遍历

思路

按位遍历,利用$n\&1$来判断最右边是否为1,然后进行无符号右移,直到二进制中不存在1为止。

代码

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int hammingWeight(uint32_t n) {
int res=0;
while(n){
res += n&1;
n >>= 1;
}
return res;
}
};

复杂度分析

  • 时间复杂度$O(logn)$。按位遍历的循环过程需要循环$logn$,其中$n$表示最高位1所在的位数
  • 空间复杂度$O(1)$。

方法二:巧用$n\&(n-1)$

思路

利用$n\&(n-1)$能将二进制数字的最右边的1变为0的性质,循环消去最右的1,计算要几次消完,就说明有几个1

代码

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int hammingWeight(uint32_t n) {
int res=0;
while(n){
res++;
n = n&(n-1);
}
return res;
}
};

复杂度分析

  • 时间复杂度$O(M)$。M为二进制中1的个数。
  • 空间复杂度$O(1)$。